<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>可配置热力图组件</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        heat: {
                            100: '#f3f4f6',
                            200: '#e5e7eb',
                            300: '#d1d5db',
                            400: '#9ca3af',
                            500: '#6b7280',
                            600: '#4b5563',
                            700: '#374151',
                            800: '#1f2937',
                            900: '#111827',
                        }
                    }
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .square-cell {
                aspect-ratio: 1/1;
            }
            .heatmap-grid {
                display: grid;
                grid-template-columns: repeat(var(--grid-cols, 10), minmax(0, 1fr));
                gap: var(--grid-gap, 1px);
            }
            .color-preview {
                width: 24px;
                height: 24px;
                border-radius: 4px;
            }
            .heatmap-container-wrapper {
                display: flex;
                justify-content: center;
                padding: 1rem;
                box-sizing: border-box;
            }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen p-4 md:p-8">
    <div class="max-w-6xl mx-auto">
        <header class="mb-8">
            <h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-gray-800 mb-2">可配置热力图组件</h1>
            <p class="text-gray-600">高度可定制的热力图可视化解决方案</p>
        </header>
        
        <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
            <div class="lg:col-span-2">
                <div class="bg-white rounded-xl shadow-lg p-6 mb-6">
                    <h3 class="font-semibold text-gray-800 mb-4">甘特图 7×23</h3>
                    <div class="heatmap-container-wrapper bg-gray-100 rounded-lg">
                        <div id="gantt-chart-1" class="max-w-full">
                            <!-- 7×23 甘特图将在这里渲染 -->
                        </div>
                    </div>
                </div>
                
                <div class="bg-white rounded-xl shadow-lg p-6">
                    <h3 class="font-semibold text-gray-800 mb-4">甘特图 7×53</h3>
                    <div class="heatmap-container-wrapper bg-gray-100 rounded-lg">
                        <div id="gantt-chart-2" class="max-w-full">
                            <!-- 7×53 甘特图将在这里渲染 -->
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="space-y-6">
                <div class="bg-white rounded-xl shadow-lg p-6">
                    <h3 class="font-semibold text-gray-800 mb-3">颜色图例</h3>
                    <div id="color-legend" class="space-y-2">
                        <div class="flex items-center">
                            <div class="w-4 h-4 rounded bg-gray-200 mr-2" id="legend-low"></div>
                            <span class="text-xs text-gray-600">0%</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-4 h-4 rounded" id="legend-low-med"></div>
                            <span class="text-xs text-gray-600">25%</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-4 h-4 rounded" id="legend-med"></div>
                            <span class="text-xs text-gray-600">50%</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-4 h-4 rounded" id="legend-high-med"></div>
                            <span class="text-xs text-gray-600">75%</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-4 h-4 rounded" id="legend-high"></div>
                            <span class="text-xs text-gray-600">100%</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 颜色工具类
        class ColorUtils {
            static hexToRgb(hex) {
                const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
                return result ? {
                    r: parseInt(result[1], 16),
                    g: parseInt(result[2], 16),
                    b: parseInt(result[3], 16)
                } : null;
            }
            
            static getColorInGradient(lowColor, highColor, ratio) {
                const r1 = lowColor.r;
                const g1 = lowColor.g;
                const b1 = lowColor.b;
                const r2 = highColor.r;
                const g2 = highColor.g;
                const b2 = highColor.b;
                
                const r = Math.round(r1 + (r2 - r1) * ratio);
                const g = Math.round(g1 + (g2 - g1) * ratio);
                const b = Math.round(b1 + (b2 - b1) * ratio);
                
                return `rgb(${r},${g},${b})`;
            }
        }
        
        // 热力图配置类
        class HeatmapConfig {
            constructor(options = {}) {
                this.rows = options.rows || 10;
                this.cols = options.cols || 10;
                this.rounded = options.rounded || 4;
                this.roundedUnit = options.roundedUnit || 'px';
                this.gap = options.gap || 1;
                this.gapUnit = options.gapUnit || 'px';
                this.maxValue = options.maxValue || 100;
                this.data = options.data || this.generateRandomData(this.rows, this.cols);
                this.lowColor = options.lowColor || '#f3f4f6';
                this.highColor = options.highColor || '#ef4444';
            }
            
            generateRandomData(rows, cols) {
                const data = [];
                for (let i = 0; i < rows; i++) {
                    data[i] = [];
                    for (let j = 0; j < cols; j++) {
                        data[i][j] = Math.floor(Math.random() * this.maxValue);
                    }
                }
                return data;
            }
        }
        
        // 热力图渲染器
        class HeatmapRenderer {
            constructor(containerId, config) {
                this.container = document.getElementById(containerId);
                this.config = config;
                this.cellClickHandler = null;
            }
            
            setCellClickHandler(handler) {
                this.cellClickHandler = handler;
                return this;
            }
            
            render() {
                this.container.innerHTML = '';
                
                // 设置网格样式
                this.container.className = 'heatmap-grid w-full';
                this.container.style.setProperty('--grid-cols', this.config.cols);
                this.container.style.setProperty('--grid-gap', `${this.config.gap}${this.config.gapUnit}`);
                
                // 渲染单元格
                for (let i = 0; i < this.config.rows; i++) {
                    for (let j = 0; j < this.config.cols; j++) {
                        const cell = document.createElement('div');
                        const value = this.config.data[i][j];
                        const percentage = Math.round((value / this.config.maxValue) * 100);
                        
                        cell.className = `square-cell transition-all duration-200 hover:scale-110 hover:shadow-md cursor-pointer relative`;
                        cell.style.borderRadius = `${this.config.rounded}${this.config.roundedUnit}`;
                        
                        // 使用颜色工具类计算颜色
                        const lowRgb = ColorUtils.hexToRgb(this.config.lowColor);
                        const highRgb = ColorUtils.hexToRgb(this.config.highColor);
                        const gradientSteps = 5;
                        const step = 100 / gradientSteps;
                        const stepIndex = Math.min(gradientSteps - 1, Math.floor(percentage / step));
                        const ratio = stepIndex / (gradientSteps - 1);
                        
                        cell.style.backgroundColor = ColorUtils.getColorInGradient(lowRgb, highRgb, ratio);
                        cell.dataset.row = i;
                        cell.dataset.col = j;
                        cell.dataset.value = value;
                        cell.dataset.percentage = percentage;
                        
                        // 添加百分比标签
                        const label = document.createElement('div');
                        label.className = 'absolute inset-0 flex items-center justify-center text-xs font-medium opacity-0 hover:opacity-100 transition-opacity';
                        label.textContent = `${percentage}%`;
                        cell.appendChild(label);
                        
                        // 添加点击事件
                        if (this.cellClickHandler) {
                            cell.addEventListener('click', () => {
                                this.cellClickHandler(i, j, value, percentage);
                                
                                // 高亮选中的单元格
                                document.querySelectorAll(`#${this.container.id} > div`).forEach(el => {
                                    el.classList.remove('ring-2', 'ring-blue-500');
                                });
                                cell.classList.add('ring-2', 'ring-blue-500');
                            });
                        }
                        
                        this.container.appendChild(cell);
                    }
                }
                
                // 更新颜色图例
                this.updateColorLegend();
            }
            
            updateColorLegend() {
                const gradientSteps = 5;
                const legendElements = [
                    document.getElementById('legend-low'),
                    document.getElementById('legend-low-med'),
                    document.getElementById('legend-med'),
                    document.getElementById('legend-high-med'),
                    document.getElementById('legend-high')
                ];
                
                const lowRgb = ColorUtils.hexToRgb(this.config.lowColor);
                const highRgb = ColorUtils.hexToRgb(this.config.highColor);
                
                for (let i = 0; i < gradientSteps; i++) {
                    const ratio = i / (gradientSteps - 1);
                    const color = ColorUtils.getColorInGradient(lowRgb, highRgb, ratio);
                    legendElements[i].style.backgroundColor = color;
                }
            }
        }
        
        // 初始化页面
        document.addEventListener('DOMContentLoaded', () => {
            // 创建第一个甘特图 (7x23)
            const gantt1Config = new HeatmapConfig({
                rows: 7,
                cols: 23,
                rounded: 5,
                roundedUnit: 'px',
                gap: 5,
                gapUnit: 'px',
                maxValue: 10
            });
            
            const gantt1Renderer = new HeatmapRenderer('gantt-chart-1', gantt1Config);
            gantt1Renderer.render();
            
            // 创建第二个甘特图 (7x53)
            const gantt2Config = new HeatmapConfig({
                rows: 7,
                cols: 53,
                rounded: 5,
                roundedUnit: 'px',
                gap: 5,
                gapUnit: 'px',
                maxValue: 10
            });
            
            const gantt2Renderer = new HeatmapRenderer('gantt-chart-2', gantt2Config);
            gantt2Renderer.render();
        });
    </script>
</body>
</html>